package com.itlong.cloud.operate.service.impl;


import com.itlong.cloud.POJO.DTO.operate.OperateDeviceQRCodePageDTO;
import com.itlong.cloud.POJO.PO.DeviceQRCodeInfoPO;
import com.itlong.cloud.POJO.VO.operate.OperateDeviceQRCodeInfoAllVO;
import com.itlong.cloud.POJO.VO.operate.OperateDeviceQRCodeInfoVO;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.constants.RedisConstant;
import com.itlong.cloud.enumerate.DataStatusEnum;
import com.itlong.cloud.operate.dao.IOperateDeviceQRCodeDao;
import com.itlong.cloud.operate.service.IOperateDeviceQRCodeService;
import com.itlong.cloud.service.RedisService;
import com.itlong.cloud.utils.data.handler.SqlUtil;
import com.itlong.cloud.utils.page.Page;
import com.itlong.cloud.utils.random.LogicIdUtil;
import com.itlong.cloud.utils.words.StringHandlerUtil;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <desc>
 *      设备二维码管理业务处理实现类
 * </desc>
 *
 * @createDate2020/2/24
 **/
@Service
@RefreshScope
public class OperateDeviceQRCodeServiceImpl implements IOperateDeviceQRCodeService {


    @Autowired
    private IOperateDeviceQRCodeDao iOperateDeviceQRCodeDao;

    @Autowired
    private RedisService redisService;

    @Value("${" + PlatformConstants.DEVICE_QR_CODE_HTML_SERVERPATH + "}")
    private String DEVICE_QR_CODE_HTML_SERVERPATH;

    /**
     * <desc>
     *      分页获取设备二维码数据
     * </desc>
     *
     * @param operateDeviceQRCodePageDTO 查询参数DTO
     * @return
     * @Author Zhu.yj
     * @createDate  2020/2/24
     */
    @Override
    public OperateDeviceQRCodeInfoAllVO getDeviceQRCodeByPage(OperateDeviceQRCodePageDTO operateDeviceQRCodePageDTO) throws Exception {
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(operateDeviceQRCodePageDTO);
        Page<OperateDeviceQRCodeInfoVO> page = new Page<>();
        page.getPage().setPageSize(operateDeviceQRCodePageDTO.getPageSize());
        page.getPage().setCurrentPage(operateDeviceQRCodePageDTO.getCurrentPage());
        params.put("pageSize",page.getPage().getPageSize());
        params.put("startSlip",page.getPage().getStartSlip());
        List<OperateDeviceQRCodeInfoVO> operateDeviceQRCodeInfoVOS = iOperateDeviceQRCodeDao.getDeviceQRCodeByPage(params);
        page.setRows(operateDeviceQRCodeInfoVOS,iOperateDeviceQRCodeDao.getDeviceQRCodePageCount(params));
        OperateDeviceQRCodeInfoAllVO operateDeviceQRCodeInfoAllVO = new OperateDeviceQRCodeInfoAllVO();
        Map<String, Object> countParams = new HashMap<>();
        //计算未使用的数量
        countParams.put("useStatus",1);
        Integer notUsedCount = iOperateDeviceQRCodeDao.getDeviceQRCodePageCount(countParams);
        //计算已使用的数量
        countParams.put("useStatus",2);
        Integer alreadyUsedCount = iOperateDeviceQRCodeDao.getDeviceQRCodePageCount(countParams);
        //计算总数量
        countParams.put("useStatus",null);
        Integer totalCount = iOperateDeviceQRCodeDao.getDeviceQRCodePageCount(countParams);
        operateDeviceQRCodeInfoAllVO.setPage(page);
        operateDeviceQRCodeInfoAllVO.setAlreadyUsedCount(alreadyUsedCount+"");
        operateDeviceQRCodeInfoAllVO.setNotUsedCount(notUsedCount+"");
        operateDeviceQRCodeInfoAllVO.setTotalCount(totalCount+"");
        return operateDeviceQRCodeInfoAllVO;
    }

    /**
     * <desc>
     *      批量保存设备二维码信息
     * </desc>
     *
     * @param  operateDeviceQRCodePageDTO 参数DTO
     * @return
     * @Author Zhu.yj
     * @createDate  2020/2/25
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Integer batchSave(OperateDeviceQRCodePageDTO operateDeviceQRCodePageDTO) throws Exception {
        List<Map<String, Object>> paramList = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMdd");
        String dayNumber = sdf.format(new Date());
        for (int i = 0; i<operateDeviceQRCodePageDTO.getAmount(); i++){
            String code = this.getQrNumber(operateDeviceQRCodePageDTO.getMyUserName(),dayNumber);
            //创建数量约束,定义-1为设备二维码今日不可创建
            if (code.contains("9999")){
                return -1;
            }
            DeviceQRCodeInfoPO deviceQRCodeInfoPO = new DeviceQRCodeInfoPO();
            deviceQRCodeInfoPO.setCode(code);
            deviceQRCodeInfoPO.setCreateUserId(operateDeviceQRCodePageDTO.getMyUserName());
            deviceQRCodeInfoPO.setOperateUserId(operateDeviceQRCodePageDTO.getMyUserName());
            deviceQRCodeInfoPO.setCreateTime(new Date());
            //刚创建是未使用状态
            deviceQRCodeInfoPO.setUseStatus(1);
            deviceQRCodeInfoPO.setStatus(DataStatusEnum.NORMAL.getType());
            String content = DEVICE_QR_CODE_HTML_SERVERPATH + "?code=" +deviceQRCodeInfoPO.getCode();
            deviceQRCodeInfoPO.setContent(content);
            paramList.add(SqlUtil.durableData(deviceQRCodeInfoPO,PlatformConstants.TABLE_SAVE));
        }
        return iOperateDeviceQRCodeDao.batchSave(paramList);
    }

    /**
     * <desc>
     *      批量更改设备二维码状态
     * </desc>
     *
     * @param operateDeviceQRCodePageDTO 更新参数DTO
     * @return 受影响行数
     * @Author Zhu.yj
     * @createDate  2020/2/25
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Integer updateStatus(OperateDeviceQRCodePageDTO operateDeviceQRCodePageDTO) throws Exception {
        Map<String,Object> params = SqlUtil.convertBeanToMapParams(operateDeviceQRCodePageDTO);
        List<String> codeList = StringHandlerUtil.splitStringList(operateDeviceQRCodePageDTO.getCodes());
        params.put("codeList",codeList);
        return iOperateDeviceQRCodeDao.updateStatus(params);
    }

    /**
     * <desc>
     *      根据code获取useStatus与status
     * </desc>
     *
     * @param codes 二维码id
     * @return
     * @Author Zhu.yj
     * @createDate  2020/3/2
     */
    @Override
    public List<Map<String, Object>> getQRCodeStatus(String codes) throws Exception {
        List<String> codeList = StringHandlerUtil.splitStringList(codes);
        return iOperateDeviceQRCodeDao.getQRCodeStatus(codeList);
    }

    /**
     * <desc>
     *      获取设备二维码编号
     * </desc>
     *
     * @return 设备二维码编号
     * @createDate 2019/12/11
     */
    private synchronized String getQrNumber(String userId, String nowDay){
        String markId = LogicIdUtil.bussinessId();
        String key = RedisConstant.DEVICE_QRCODE_REDIS_KEY + nowDay;
        Long time = RedisConstant.DEVICE_QRCODE_REDIS_CACHE_TIME;
        // 获取当日最小可用编号
        String qrNumber = redisService.get(key);
        if (StringUtils.isBlank(qrNumber) || !this.getLongValue(qrNumber, -1L).equals(-1L)) {
            // 拿到正常的之后赶紧先放一个唯一标志的进去，尽可能规避并发情况
            redisService.set(key, time, markId + "_" + userId);
        } else {
            // 递归
            return getQrNumber(userId, nowDay);
        }
        if (StringUtils.isBlank(qrNumber)) {
            String qrNumberData = iOperateDeviceQRCodeDao.getMaxQRNumberNowDay(nowDay);
            if (StringUtils.isBlank(qrNumberData)) {
                // 数据库中没有，则当天第一次开始
                qrNumber = nowDay + "0001";
                String markValue = redisService.get(key);
                // 获取的值与一开始放入的唯一标志相等，则完成此次获取，并设置下次可用的二维码编号
                if ((markId + "_" + userId).equals(markValue)) {
                    redisService.set(key, time, new Long(qrNumber) + 1 + "");
                    return qrNumber;
                } else {
                    // 失败了之后再重新拿
                    return getQrNumber(userId, nowDay);
                }
            } else {
                // 数据库中有，则从最大二维码编号+1开始
                qrNumber = new Long(qrNumberData) + 1 + "";
                String markValue = redisService.get(key);
                // 获取的值与一开始放入的唯一标志相等，则完成此次获取，并设置下次可用的二维码编号
                if ((markId + "_" + userId).equals(markValue)) {
                    redisService.set(key, time, new Long(qrNumber) + 1 + "");
                    return qrNumber;
                } else {
                    // 失败了之后再重新拿
                    return getQrNumber(userId, nowDay);
                }
            }
        } else {
            // 缓存中已经有今天的设备二维码编号
            String markValue = redisService.get(key);
            // 获取的值与一开始放入的唯一标志相等，则完成此次获取，并设置下次可用的二维码编号
            if ((markId + "_" + userId).equals(markValue)) {
                redisService.set(key, time, new Long(qrNumber) + 1 + "");
                return qrNumber;
            } else {
                // 失败了之后再重新拿
                return getQrNumber(userId, nowDay);
            }
        }
    }

    /**
     * <desc>
     *      String转Long，异常返回默认值
     * </desc>
     *
     * @return 设备二维码编号
     * @author wangzhi
     * @createDate 2019/12/11
     */
    private Long getLongValue(String str, Long defaultValue) {
        try {
            return new Long(str);
        } catch (Exception e) {
            return defaultValue;
        }
    }

}
